package com.sukaiyi.generator.ui;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.sukaiyi.generator.actions.model.ActionContext;
import com.sukaiyi.generator.config.PluginConfig;
import com.sukaiyi.generator.config.model.StructTemplate;
import com.sukaiyi.generator.processor.PersistenceProcessor;
import com.sukaiyi.generator.processor.SqlParser;
import com.sukaiyi.generator.processor.TemplateProcessor;
import com.sukaiyi.generator.processor.model.ClassInfo;
import com.sukaiyi.generator.utils.IdeaUIUtils;
import com.intellij.ide.highlighter.DTDFileType;
import com.intellij.json.JsonFileType;
import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.PsiDirectory;
import com.intellij.ui.EditorTextField;
import freemarker.template.TemplateException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;

/**
 * @author sukaiyi
 */
public class GeneratorStepDialog extends DialogWrapper {
    private ActionContext actionContext;
    private JPanel contentPane;

    private JTextPane ddForExampleTextPane;
    // step 1
    private JPanel cardPanel1DDL;
    private TemplateComboBox templateBox;
    private EditorTextField ddlTextField;
    // step 2
    private JPanel cardPanel2DataModel;
    private EditorTextField dataModelTextField;
    // step 3
    private JPanel cardPanel3Preview;
    private GeneratedCodePreviewer generatedCodePreviewer;

    private Map<Component, Function<Void, Boolean>> nextActionPanelMap;

    private Map<String, Object> dataModel;
    private StructTemplate template;

    private Action previousAction;
    private Action nextAction;
    private int currentIndex = 1;

    public GeneratorStepDialog(ActionContext context) {
        super(context.getProject());
        this.actionContext = context;
        this.init();
        this.setTitle("Generate Code From DDL");
        ddForExampleTextPane.setText("CREATE TABLE `user` (\n" +
                "  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',\n" +
                "  `username` varchar(255) DEFAULT NULL COMMENT 'User name',\n" +
                "  PRIMARY KEY (`id`)\n" +
                ") ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='User table'");
        dataModel = new LinkedHashMap<>();
        contentPane.registerKeyboardAction(e -> dispose(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        contentPane.setPreferredSize(new Dimension(800, 400));
        nextActionPanelMap = new HashMap<>();
        nextActionPanelMap.put(cardPanel1DDL, (v) -> {
            template = templateBox.getSelectedItem();
            String ddl = ddlTextField.getText();
            try {
                ClassInfo classInfo = SqlParser.parse(ddl);
                PsiDirectory directory = actionContext.getDirectory();
                ItemPresentation itemPresentation = directory.getPresentation();
                assert itemPresentation != null;
                String pkg = itemPresentation.getLocationString();
                dataModel.clear();
                dataModel.putAll(PluginConfig.getInstance().globalVariable);
                dataModel.put("pkg", pkg);
                dataModel.put("entityName", classInfo.getClassName());
                dataModel.put("entityNameLowerCase", StrUtil.lowerFirst(classInfo.getClassName()));
                dataModel.put("tableName", classInfo.getTableName());
                dataModel.put("date", DateUtil.today());
                dataModel.put("classComment", classInfo.getClassComment());
                dataModel.put("fields", classInfo.getFieldList());
                dataModelTextField.setText(JSONUtil.toJsonPrettyStr(dataModel));
            } catch (Exception e) {
                return false;
            }
            return true;
        });
        nextActionPanelMap.put(cardPanel2DataModel, (v) -> {
            String dataModelStr = dataModelTextField.getText();
            if (!JSONUtil.isJson(dataModelStr)) {
                return false;
            }
            dataModel = JSONUtil.parseObj(dataModelStr);
            try {
                StructTemplate generated = TemplateProcessor.getInstance().process(dataModel, template);
                generatedCodePreviewer.setStructTemplate(generated);
            } catch (IOException | TemplateException e) {
                e.printStackTrace();
                return false;
            }
            setOKActionEnabled(true);
            return true;
        });
        setOKActionEnabled(false);
    }

    @Nullable
    @Override
    protected String getDimensionServiceKey() {
        return this.getClass().getName();
    }

    @Nullable
    @Override
    protected JComponent createCenterPanel() {
        return contentPane;
    }

    @NotNull
    @Override
    protected Action[] createActions() {
        return new Action[]{getPreviousAction(), getNextAction(), getOKAction(), getCancelAction()};
    }

    private Action getNextAction() {
        nextAction = new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (nextActionPanelMap.get(contentPane.getComponent(currentIndex - 1)).apply(null)) {
                    CardLayout layout = (CardLayout) contentPane.getLayout();
                    layout.next(contentPane);
                    currentIndex++;
                    updateButtonStatus(currentIndex, contentPane);
                }
            }
        };
        nextAction.putValue(Action.NAME, "Next");
        return nextAction;
    }

    private Action getPreviousAction() {
        previousAction = new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                setOKActionEnabled(false);
                CardLayout layout = (CardLayout) contentPane.getLayout();
                layout.previous(contentPane);
                currentIndex--;
                updateButtonStatus(currentIndex, contentPane);
            }
        };
        previousAction.setEnabled(false);
        previousAction.putValue(Action.NAME, "Previous");
        return previousAction;
    }

    private void updateButtonStatus(int currentIndex, JPanel contentPane) {
        if (currentIndex == 1) {
            previousAction.setEnabled(false);
            nextAction.setEnabled(true);
        } else if (currentIndex == contentPane.getComponentCount()) {
            previousAction.setEnabled(true);
            nextAction.setEnabled(false);
        } else {
            previousAction.setEnabled(true);
            nextAction.setEnabled(true);
        }
    }

    @Override
    protected void doOKAction() {
        StructTemplate template = generatedCodePreviewer.getEditedStructTemplate();
        WriteCommandAction.runWriteCommandAction(actionContext.getProject(), () -> PersistenceProcessor.getInstance().process(actionContext, template));
        super.doOKAction();
    }

    private void createUIComponents() {
        ddlTextField = IdeaUIUtils.createEditorTextField(actionContext.getProject(), DTDFileType.INSTANCE);
        ddlTextField.setPlaceholder("Paste DDL here");
        dataModelTextField = IdeaUIUtils.createEditorTextField(actionContext.getProject(), JsonFileType.INSTANCE);
        generatedCodePreviewer = new GeneratedCodePreviewer(actionContext.getProject(), null);
    }
}
